﻿using Microsoft.EntityFrameworkCore;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Threading.Tasks;

namespace UnitOfWorkEF.SqlServer.Domain
{


    /// <summary>
    /// 基础仓库类（不推荐重写时调用内部方法，建议使用EFcore原生方法重写）
    /// </summary>
    /// <typeparam name="T"></typeparam>
    public abstract class UnitOfWorkBaseRepository<T> : IUnitOfWorkBaseRepository<T> where T : class
    {
        /// <summary>
        /// 数据库对象
        /// </summary>
        private  UnitOfWorkDbContext nDbContext;
        /// <summary>
        /// 实体对象
        /// </summary>
        protected readonly DbSet<T> nEntities;
        DbSet<T> IUnitOfWorkBaseRepository<T>.Table => nEntities;
        /// <summary>
        /// 工作单元对象
        /// </summary>
        public IUnitOfWork UnitOfWork => nDbContext;

        protected UnitOfWorkBaseRepository(UnitOfWorkDbContext dbContext)
        {
            nDbContext = dbContext;
            nEntities = dbContext.Set<T>();
        }

        async Task<bool> IUnitOfWorkBaseRepository<T>.ExistAsync(Expression<Func<T, bool>> anyLambda) => await nEntities.AnyAsync(anyLambda);
        async Task<T> IUnitOfWorkBaseRepository<T>.FindAsync(Expression<Func<T, bool>> whereLambda) => await nEntities.FirstAsync<T>(whereLambda);
        async Task<T> IUnitOfWorkBaseRepository<T>.AddAsync(T entity) => (await nEntities.AddAsync(entity)).Entity;
        //??EF自带的删除为什么没异步
        async Task<T> IUnitOfWorkBaseRepository<T>.RemoveAsync(T entity) => await Task.Run(() => nEntities.Remove(entity).Entity);
        //??EF自带的更新为什么没异步
        async Task<T> IUnitOfWorkBaseRepository<T>.UpdateAsync(T entity) => await Task.Run(() => nEntities.Update(entity).Entity);
        //??EF自带的更新为什么没异步
        async Task IUnitOfWorkBaseRepository<T>.UpdateRange(IEnumerable<T> entities) => await Task.Run(() => nEntities.UpdateRange(entities));

        async Task<List<T>> IUnitOfWorkBaseRepository<T>.FindRangeAsync(Expression<Func<T, bool>> whereLamdba, string orderName, bool isAsc) => await OrderBy(nEntities.Where(whereLamdba), orderName, isAsc).ToListAsync();

        async Task<(List<T>, int)> IUnitOfWorkBaseRepository<T>.FindRangePageAsync(int pageIndex, int pageSize, Expression<Func<T, bool>> whereLamdba, string orderName, bool isAsc)
        {
            var _list = nEntities.Where(whereLamdba);
            var _total = _list;

            _list = OrderBy(_list, orderName, isAsc).Skip<T>((pageIndex - 1) * pageSize).Take<T>(pageSize);

            var _list_t = _list.ToListAsync();
            var _total_t = _total.CountAsync();

            await Task.WhenAll(_list_t, _total_t);
            return (_list_t.Result, _total_t.Result);
        }

        /// <summary>
        /// 排序(防混淆封为内部方法)
        /// </summary>
        /// <param name="source">数据源</param>
        /// <param name="propertyName">排序字段</param>
        /// <param name="isAsc">是否升序</param>
        /// <returns>排序结果</returns>
        protected IQueryable<T> OrderBy(IQueryable<T> source, string propertyName, bool isAsc)
        {
            if (source == null) throw new ArgumentNullException("source", "不能为空");
            if (string.IsNullOrEmpty(propertyName)) return source;
            var _parameter = Expression.Parameter(source.ElementType);
            var _property = Expression.Property(_parameter, propertyName);
            var _lambda = Expression.Lambda(_property, _parameter);
            var _methodName = isAsc ? "OrderBy" : "OrderByDescending";
            var _resultExpression = Expression.Call(typeof(Queryable), _methodName, new Type[] { source.ElementType, _property.Type }, source.Expression, Expression.Quote(_lambda));
            return source.Provider.CreateQuery<T>(_resultExpression);
        }

        ~UnitOfWorkBaseRepository()
        {
            if (nDbContext != null)
            {
                nDbContext.Dispose();
                nDbContext = null;
            }
        }
    }
}


